package com.umeox.watch.moto.launcher.widget;

import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

import com.umeox.moto.common.log.Logger;
import com.umeox.watch.moto.launcher.R;

import java.util.Calendar;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

/**
 * 指针时钟
 */
public class AnalogClock extends View {
    public static final int WHAT = 500;
    private final Calendar mCalendar;
    private final Paint mHandPaint;
    private static final float HAND_END_CAP_RADIUS = 4f;
    private static final float STROKE_WIDTH = 4f;
    private static final int SHADOW_RADIUS = 6;
    private float mHoursHandLength;
    private Bitmap mMinutesBitmap;
    private Bitmap mHourBitmap;
    private Bitmap mSecondsBitmap;
    private int mMinutesHandLength;
    private int mSecondsHandLength;
    private float mHourHandOffsetWidth;
    private float mMinutesHandOffsetWidth;
    private float mSecondsHandOffsetWidth;
    private float mHandNailOffset;
    private float mSecondHandNailOffset;
    private PaintFlagsDrawFilter mDrawFilter;

    private static final String TAG = "AnalogClock";
    private static final long INTERACTIVE_UPDATE_RATE_MS = TimeUnit.SECONDS.toMillis(1);
    @SuppressLint("HandlerLeak")
    private final Handler mUpdateTimeHandler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            if (WHAT == message.what) {
                invalidate();
                long timeMs = System.currentTimeMillis();
                long delayMs = INTERACTIVE_UPDATE_RATE_MS
                        - (timeMs % INTERACTIVE_UPDATE_RATE_MS);

                mUpdateTimeHandler.sendEmptyMessageDelayed(WHAT, delayMs);
            }
        }
    };

    public AnalogClock(Context context) {
        this(context, null);
    }

    public AnalogClock(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public void setHandNail(float handNailOffset) {
        mHandNailOffset = handNailOffset;
        postInvalidate();
    }

    public AnalogClock(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.AnalogClock, defStyleAttr, 0);
        mHandNailOffset = array.getDimension(R.styleable.AnalogClock_hand_nail, 0f);
        mSecondHandNailOffset = array.getDimension(R.styleable.AnalogClock_hand_seconds_nail, 0f);
        mHourBitmap = getHandBitmap(array, R.styleable.AnalogClock_hand_hours);
        mMinutesBitmap = getHandBitmap(array, R.styleable.AnalogClock_hand_minutes);
        mSecondsBitmap = getHandBitmap(array, R.styleable.AnalogClock_hand_seconds);
        array.recycle();
        initHourHandSize();
        initMinutesHandSize();
        initSecondHandSize();

        mHandPaint = new Paint();
        mHandPaint.setColor(Color.WHITE);
        mHandPaint.setAntiAlias(true);
        mHandPaint.setStyle(Paint.Style.STROKE);
        mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
        mCalendar = Calendar.getInstance();

    }

    private void initHourHandSize() {
        if (mHourBitmap != null) {
            mHoursHandLength = mHourBitmap.getHeight();
            mHourHandOffsetWidth = mHourBitmap.getWidth() / 2f;
        }
    }

    private void initMinutesHandSize() {
        if (mMinutesBitmap != null) {
            mMinutesHandLength = mMinutesBitmap.getHeight();
            mMinutesHandOffsetWidth = mMinutesBitmap.getWidth() / 2f;
        }
    }

    private void initSecondHandSize() {
        if (mSecondsBitmap != null) {
            mSecondsHandLength = mSecondsBitmap.getHeight();
            mSecondsHandOffsetWidth = mSecondsBitmap.getWidth() / 2f;
        }
    }

    public void setHandMinuteResources(int resourceId) {
        mMinutesBitmap = getHandBitmap(resourceId);
        postInvalidate();
    }

    public void setHandHourResources(int resourceId) {
        mHourBitmap = getHandBitmap(resourceId);
        postInvalidate();
    }


    public void setHandSecondResources(int resourceId) {
        mSecondsBitmap = getHandBitmap(resourceId);
        postInvalidate();
    }

    private Bitmap getHandBitmap(int resourceId) {
        return BitmapFactory.decodeResource(getResources(), resourceId);
    }

    public void setHandMinutesBitmap(Bitmap minutesBitmap) {
        mMinutesBitmap = minutesBitmap;
        initMinutesHandSize();
        postInvalidate();
    }

    public void setHandHourBitmap(Bitmap hourBitmap) {
        mHourBitmap = hourBitmap;
        initHourHandSize();
        postInvalidate();
    }

    public void setHandSecondsBitmap(Bitmap secondsBitmap) {
        mSecondsBitmap = secondsBitmap;
        initSecondHandSize();
        postInvalidate();
    }

    private Bitmap getHandBitmap(TypedArray array, int resId) {
        final int resourceId = array.getResourceId(resId, 0);
        if (resourceId == 0) {
            return null;
        }
        return getHandBitmap(resourceId);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        updateTimer();
        getContext().registerReceiver(mTimeZoneReceiver, new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED));
    }

    private final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {

            invalidate();
        }
    };

    @Override
    protected void onDetachedFromWindow() {
        Logger.e("============onDetachedFromWindow=============");
        super.onDetachedFromWindow();
        mUpdateTimeHandler.removeMessages(WHAT);
        getContext().unregisterReceiver(mTimeZoneReceiver);
    }

    private void updateTimer() {
        mUpdateTimeHandler.removeMessages(WHAT);
        mUpdateTimeHandler.sendEmptyMessage(WHAT);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        long now = System.currentTimeMillis();
        canvas.setDrawFilter(mDrawFilter);
        mCalendar.setTimeInMillis(now);
        mCalendar.setTimeZone(TimeZone.getDefault());
        final float seconds =
                (mCalendar.get(Calendar.SECOND) + mCalendar.get(Calendar.MILLISECOND) / 1000f);
        final float secondsRotation = seconds * 6f;

        final float minutesRotation = mCalendar.get(Calendar.MINUTE) * 6f;

        final float hourHandOffset = mCalendar.get(Calendar.MINUTE) / 2f;
        final float hoursRotation = (mCalendar.get(Calendar.HOUR) * 30) + hourHandOffset;

        canvas.save();

        float centerX = 120f;
        float centerY = 120f;
        if (mHourBitmap != null) {
            canvas.rotate(hoursRotation, centerX, centerY);
            canvas.drawBitmap(mHourBitmap, centerX - mHourHandOffsetWidth, centerY - mHoursHandLength + mHandNailOffset, mHandPaint);
        }

        if (mMinutesBitmap != null) {
            canvas.rotate(minutesRotation - hoursRotation, centerX, centerY);
            canvas.drawBitmap(mMinutesBitmap, centerX - mMinutesHandOffsetWidth, centerY - mMinutesHandLength + mHandNailOffset, mHandPaint);
        }

        if (mSecondsBitmap != null) {
            canvas.rotate(secondsRotation - minutesRotation, centerX, centerY);
            canvas.drawBitmap(mSecondsBitmap, centerX - mSecondsHandOffsetWidth, centerY - mSecondsHandLength + mSecondHandNailOffset, mHandPaint);
        }

        canvas.restore();
    }

    public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) {
        mOnTimeChangedListener = onTimeChangedListener;
    }

    private OnTimeChangedListener mOnTimeChangedListener;

    public void setSecondHandNailOffset(float secondHandNailOffset) {
        mSecondHandNailOffset = secondHandNailOffset;
        postInvalidate();
    }

    public interface OnTimeChangedListener {
        void onTimeChange(long time);
    }
}
